package com.yookey.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wf.captcha.ArithmeticCaptcha;
import com.yookey.common.constant.ResponseMessage;
import com.yookey.common.context.AccountUtils;
import com.yookey.common.exception.BusinessException;
import com.yookey.common.result.Result;
import com.yookey.common.utils.JWTUtil;
import com.yookey.common.utils.MD5Util;
import com.yookey.model.dto.AccountDTO;
import com.yookey.model.dto.LoginAuthDTO;
import com.yookey.model.entity.Account;
import com.yookey.service.AccountService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author yww
 * @date 2020/9/29
 */
@RestController
public class LoginController {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private AccountService accountService;

    @ApiOperation(value = "用户登录")
    @PostMapping("/login")
    public Result login(@RequestBody @Valid LoginAuthDTO loginAuthDTO) {
        // 验证码校验
        if (!captchaImageVerify(loginAuthDTO)) {
            return Result.error(ResponseMessage.VERIFYCODEERROR);
        }
        Account account = accountService.getOne(new QueryWrapper<Account>().eq("username", loginAuthDTO.getUsername()));
        if (account == null || !MD5Util.getMD5(loginAuthDTO.getPassword()).equals(account.getPassword())) {
            return Result.error(ResponseMessage.NODATA.getCode(), "用户名或密码错误");
        }
        if(account.getStatus() == 0){
            return Result.error(ResponseMessage.ACCOUNT_FORBIDDEN);
        }

        AccountDTO accountDTO = new AccountDTO();
        BeanUtils.copyProperties(account, accountDTO);
        // 签发用户token
        String token = JWTUtil.generateToken(accountDTO);
        // 返回 token
        return Result.success(token, "登录成功");
    }

    @ApiOperation(value = "退出登录")
    @PostMapping("/logout")
    public Result logout() {
        AccountDTO accountDTO = AccountUtils.get();
        JWTUtil.logoutToken(accountDTO.getRefreshToken());
        return Result.success("退出成功");
    }

    @ApiOperation(value = "用户注册")
    @PostMapping("/register")
    public Result registerUser(@RequestBody AccountDTO accountDTO) {
        return accountService.add(accountDTO);
    }

    @ApiOperation(value = "获取验证码")
    @GetMapping(value = "/login/captchaImage")
    public Result<Map<String, Object>> getCode() {
        // 算术类型 https://gitee.com/whvse/EasyCaptcha
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36);
        // 几位数运算，默认是两位
        captcha.setLen(2);
        // 获取运算的结果
        String result = captcha.text();
        String uuid = IdUtil.simpleUUID();
        // 保存
        redisTemplate.opsForValue().set(uuid, result, TimeUnit.SECONDS.toSeconds(2));
        // 验证码信息
        Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
            put("img", captcha.toBase64());
            put("uuid", uuid);
        }};
        return Result.success(imgResult);
    }


    /**
     * 验证码校验
     *
     * @param loginAuthDTO 用户登陆参数
     */
    private boolean captchaImageVerify(LoginAuthDTO loginAuthDTO) {
        // 查询验证码
        String code = redisTemplate.opsForValue().get(loginAuthDTO.getUuid());
        // 删除redis中的验证码
        redisTemplate.delete(loginAuthDTO.getUuid());
        // 验证码校验
        if (StrUtil.isBlank(code)) {
            throw new BusinessException(String.valueOf(ResponseMessage.PARAMNOTEXIST.getCode()), "验证码不存在或已过期");
        }

        return loginAuthDTO.getCode().equalsIgnoreCase(code.trim());
    }

}
